package com.marketing.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.marketing.auth.dto.*;
import com.marketing.auth.entity.*;
import com.marketing.auth.mapper.*;
import com.marketing.auth.service.RbacService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * RBAC权限管理服务实现类
 */
@Service
public class RbacServiceImpl implements RbacService {

    private static final Logger logger = LoggerFactory.getLogger(RbacServiceImpl.class);

    @Autowired
    private RoleMapper roleMapper;
    
    @Autowired
    private ResourceMapper resourceMapper;
    
    @Autowired
    private PermissionMapper permissionMapper;
    
    @Autowired
    private UserRoleMapper userRoleMapper;
    
    @Autowired
    private RolePermissionMapper rolePermissionMapper;

    // ============== 角色管理 ==============

    @Override
    @Transactional
    public Role createRole(Role role, String operator) {
        logger.info("开始创建角色，角色编码: {}, 操作者: {}", role.getRoleCode(), operator);
        
        try {
            role.setCreateBy(operator);
            role.setUpdateBy(operator);
            role.setCreateTime(LocalDateTime.now());
            role.setUpdateTime(LocalDateTime.now());
            
            int result = roleMapper.insert(role);
            if (result > 0) {
                logger.info("角色创建成功，角色ID: {}, 角色编码: {}, 操作者: {}", role.getId(), role.getRoleCode(), operator);
                return role;
            } else {
                logger.error("角色创建失败，数据库插入失败，角色编码: {}", role.getRoleCode());
                throw new RuntimeException("角色创建失败");
            }
        } catch (Exception e) {
            logger.error("角色创建过程中发生异常，角色编码: {}, 操作者: {}, 异常: {}", role.getRoleCode(), operator, e.getMessage(), e);
            throw new RuntimeException("角色创建失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public Role updateRole(Role role, String operator) {
        logger.info("开始更新角色，角色ID: {}, 操作者: {}", role.getId(), operator);
        
        try {
            role.setUpdateBy(operator);
            role.setUpdateTime(LocalDateTime.now());
            
            int result = roleMapper.updateById(role);
            if (result > 0) {
                logger.info("角色更新成功，角色ID: {}, 角色编码: {}, 操作者: {}", role.getId(), role.getRoleCode(), operator);
                return role;
            } else {
                logger.error("角色更新失败，数据库更新失败，角色ID: {}", role.getId());
                throw new RuntimeException("角色更新失败");
            }
        } catch (Exception e) {
            logger.error("角色更新过程中发生异常，角色ID: {}, 操作者: {}, 异常: {}", role.getId(), operator, e.getMessage(), e);
            throw new RuntimeException("角色更新失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public boolean deleteRole(Long roleId, String operator) {
        logger.info("开始删除角色，角色ID: {}, 操作者: {}", roleId, operator);
        
        try {
            // 1. 删除角色权限关联
            rolePermissionMapper.deleteByRoleId(roleId);
            logger.debug("删除角色权限关联成功，角色ID: {}", roleId);
            
            // 2. 删除用户角色关联
            userRoleMapper.deleteByRoleId(roleId);
            logger.debug("删除用户角色关联成功，角色ID: {}", roleId);
            
            // 3. 删除角色
            int result = roleMapper.deleteById(roleId);
            if (result > 0) {
                logger.info("角色删除成功，角色ID: {}, 操作者: {}", roleId, operator);
                return true;
            } else {
                logger.error("角色删除失败，数据库删除失败，角色ID: {}", roleId);
                return false;
            }
        } catch (Exception e) {
            logger.error("角色删除过程中发生异常，角色ID: {}, 操作者: {}, 异常: {}", roleId, operator, e.getMessage(), e);
            throw new RuntimeException("角色删除失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Role getRoleById(Long roleId) {
        logger.debug("根据ID查询角色，角色ID: {}", roleId);
        return roleMapper.selectById(roleId);
    }

    @Override
    public List<Role> getAllRoles() {
        logger.debug("查询所有启用的角色");
        return roleMapper.selectEnabledRoles();
    }

    // ============== 资源管理 ==============

    @Override
    @Transactional
    public Resource createResource(Resource resource, String operator) {
        logger.info("开始创建资源，资源编码: {}, 操作者: {}", resource.getResourceCode(), operator);
        
        try {
            resource.setCreateBy(operator);
            resource.setUpdateBy(operator);
            resource.setCreateTime(LocalDateTime.now());
            resource.setUpdateTime(LocalDateTime.now());
            
            int result = resourceMapper.insert(resource);
            if (result > 0) {
                logger.info("资源创建成功，资源ID: {}, 资源编码: {}, 操作者: {}", resource.getId(), resource.getResourceCode(), operator);
                return resource;
            } else {
                logger.error("资源创建失败，数据库插入失败，资源编码: {}", resource.getResourceCode());
                throw new RuntimeException("资源创建失败");
            }
        } catch (Exception e) {
            logger.error("资源创建过程中发生异常，资源编码: {}, 操作者: {}, 异常: {}", resource.getResourceCode(), operator, e.getMessage(), e);
            throw new RuntimeException("资源创建失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public Resource updateResource(Resource resource, String operator) {
        logger.info("开始更新资源，资源ID: {}, 操作者: {}", resource.getId(), operator);
        
        try {
            resource.setUpdateBy(operator);
            resource.setUpdateTime(LocalDateTime.now());
            
            int result = resourceMapper.updateById(resource);
            if (result > 0) {
                logger.info("资源更新成功，资源ID: {}, 资源编码: {}, 操作者: {}", resource.getId(), resource.getResourceCode(), operator);
                return resource;
            } else {
                logger.error("资源更新失败，数据库更新失败，资源ID: {}", resource.getId());
                throw new RuntimeException("资源更新失败");
            }
        } catch (Exception e) {
            logger.error("资源更新过程中发生异常，资源ID: {}, 操作者: {}, 异常: {}", resource.getId(), operator, e.getMessage(), e);
            throw new RuntimeException("资源更新失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public boolean deleteResource(Long resourceId, String operator) {
        logger.info("开始删除资源，资源ID: {}, 操作者: {}", resourceId, operator);
        
        try {
            // 1. 查询关联的权限
            List<Permission> permissions = permissionMapper.selectByResourceId(resourceId);
            if (!permissions.isEmpty()) {
                for (Permission permission : permissions) {
                    // 删除角色权限关联
                    rolePermissionMapper.deleteByPermissionId(permission.getId());
                    // 删除权限
                    permissionMapper.deleteById(permission.getId());
                }
                logger.debug("删除资源关联的权限成功，资源ID: {}, 权限数量: {}", resourceId, permissions.size());
            }
            
            // 2. 递归删除子资源
            List<Resource> children = resourceMapper.selectByParentId(resourceId);
            for (Resource child : children) {
                deleteResource(child.getId(), operator);
            }
            
            // 3. 删除资源
            int result = resourceMapper.deleteById(resourceId);
            if (result > 0) {
                logger.info("资源删除成功，资源ID: {}, 操作者: {}", resourceId, operator);
                return true;
            } else {
                logger.error("资源删除失败，数据库删除失败，资源ID: {}", resourceId);
                return false;
            }
        } catch (Exception e) {
            logger.error("资源删除过程中发生异常，资源ID: {}, 操作者: {}, 异常: {}", resourceId, operator, e.getMessage(), e);
            throw new RuntimeException("资源删除失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Resource getResourceById(Long resourceId) {
        logger.debug("根据ID查询资源，资源ID: {}", resourceId);
        return resourceMapper.selectById(resourceId);
    }

    @Override
    public List<Resource> getAllResources() {
        logger.debug("查询所有启用的资源");
        return resourceMapper.selectEnabledResources();
    }

    @Override
    public List<ResourceDto> getResourceTree() {
        logger.debug("构建资源树");
        
        try {
            List<Resource> allResources = resourceMapper.selectEnabledResources();
            return buildResourceTree(allResources, 0L);
        } catch (Exception e) {
            logger.error("构建资源树失败，异常: {}", e.getMessage(), e);
            throw new RuntimeException("构建资源树失败", e);
        }
    }

    // ============== 权限管理 ==============

    @Override
    @Transactional
    public Permission createPermission(Permission permission, String operator) {
        logger.info("开始创建权限，权限编码: {}, 操作者: {}", permission.getPermissionCode(), operator);
        
        try {
            permission.setCreateBy(operator);
            permission.setUpdateBy(operator);
            permission.setCreateTime(LocalDateTime.now());
            permission.setUpdateTime(LocalDateTime.now());
            
            int result = permissionMapper.insert(permission);
            if (result > 0) {
                logger.info("权限创建成功，权限ID: {}, 权限编码: {}, 操作者: {}", permission.getId(), permission.getPermissionCode(), operator);
                return permission;
            } else {
                logger.error("权限创建失败，数据库插入失败，权限编码: {}", permission.getPermissionCode());
                throw new RuntimeException("权限创建失败");
            }
        } catch (Exception e) {
            logger.error("权限创建过程中发生异常，权限编码: {}, 操作者: {}, 异常: {}", permission.getPermissionCode(), operator, e.getMessage(), e);
            throw new RuntimeException("权限创建失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public Permission updatePermission(Permission permission, String operator) {
        logger.info("开始更新权限，权限ID: {}, 操作者: {}", permission.getId(), operator);
        
        try {
            permission.setUpdateBy(operator);
            permission.setUpdateTime(LocalDateTime.now());
            
            int result = permissionMapper.updateById(permission);
            if (result > 0) {
                logger.info("权限更新成功，权限ID: {}, 权限编码: {}, 操作者: {}", permission.getId(), permission.getPermissionCode(), operator);
                return permission;
            } else {
                logger.error("权限更新失败，数据库更新失败，权限ID: {}", permission.getId());
                throw new RuntimeException("权限更新失败");
            }
        } catch (Exception e) {
            logger.error("权限更新过程中发生异常，权限ID: {}, 操作者: {}, 异常: {}", permission.getId(), operator, e.getMessage(), e);
            throw new RuntimeException("权限更新失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public boolean deletePermission(Long permissionId, String operator) {
        logger.info("开始删除权限，权限ID: {}, 操作者: {}", permissionId, operator);
        
        try {
            // 1. 删除角色权限关联
            rolePermissionMapper.deleteByPermissionId(permissionId);
            logger.debug("删除角色权限关联成功，权限ID: {}", permissionId);
            
            // 2. 删除权限
            int result = permissionMapper.deleteById(permissionId);
            if (result > 0) {
                logger.info("权限删除成功，权限ID: {}, 操作者: {}", permissionId, operator);
                return true;
            } else {
                logger.error("权限删除失败，数据库删除失败，权限ID: {}", permissionId);
                return false;
            }
        } catch (Exception e) {
            logger.error("权限删除过程中发生异常，权限ID: {}, 操作者: {}, 异常: {}", permissionId, operator, e.getMessage(), e);
            throw new RuntimeException("权限删除失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Permission getPermissionById(Long permissionId) {
        logger.debug("根据ID查询权限，权限ID: {}", permissionId);
        return permissionMapper.selectById(permissionId);
    }

    @Override
    public List<Permission> getAllPermissions() {
        logger.debug("查询所有启用的权限");
        return permissionMapper.selectEnabledPermissions();
    }

    // ============== 权限分配 ==============

    @Override
    @Transactional
    public boolean assignRolesToUser(Long userId, List<Long> roleIds, String operator) {
        logger.info("开始为用户分配角色，用户ID: {}, 角色ID列表: {}, 操作者: {}", userId, roleIds, operator);
        
        try {
            // 1. 删除用户现有的角色
            userRoleMapper.deleteByUserId(userId);
            logger.debug("删除用户现有角色成功，用户ID: {}", userId);
            
            // 2. 分配新的角色
            if (roleIds != null && !roleIds.isEmpty()) {
                for (Long roleId : roleIds) {
                    UserRole userRole = new UserRole(userId, roleId, operator);
                    userRoleMapper.insert(userRole);
                }
                logger.debug("为用户分配新角色成功，用户ID: {}, 角色数量: {}", userId, roleIds.size());
            }
            
            logger.info("用户角色分配完成，用户ID: {}, 操作者: {}", userId, operator);
            return true;
        } catch (Exception e) {
            logger.error("用户角色分配过程中发生异常，用户ID: {}, 操作者: {}, 异常: {}", userId, operator, e.getMessage(), e);
            throw new RuntimeException("用户角色分配失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public boolean assignPermissionsToRole(Long roleId, List<Long> permissionIds, String operator) {
        logger.info("开始为角色分配权限，角色ID: {}, 权限ID列表: {}, 操作者: {}", roleId, permissionIds, operator);
        
        try {
            // 1. 删除角色现有的权限
            rolePermissionMapper.deleteByRoleId(roleId);
            logger.debug("删除角色现有权限成功，角色ID: {}", roleId);
            
            // 2. 分配新的权限
            if (permissionIds != null && !permissionIds.isEmpty()) {
                for (Long permissionId : permissionIds) {
                    RolePermission rolePermission = new RolePermission(roleId, permissionId, operator);
                    rolePermissionMapper.insert(rolePermission);
                }
                logger.debug("为角色分配新权限成功，角色ID: {}, 权限数量: {}", roleId, permissionIds.size());
            }
            
            logger.info("角色权限分配完成，角色ID: {}, 操作者: {}", roleId, operator);
            return true;
        } catch (Exception e) {
            logger.error("角色权限分配过程中发生异常，角色ID: {}, 操作者: {}, 异常: {}", roleId, operator, e.getMessage(), e);
            throw new RuntimeException("角色权限分配失败: " + e.getMessage(), e);
        }
    }

    // ============== 权限查询 ==============

    @Override
    public List<Role> getUserRoles(Long userId) {
        logger.debug("查询用户角色，用户ID: {}", userId);
        return roleMapper.selectRolesByUserId(userId);
    }

    @Override
    public List<Permission> getUserPermissions(Long userId) {
        logger.debug("查询用户权限，用户ID: {}", userId);
        return permissionMapper.selectPermissionsByUserId(userId);
    }

    @Override
    public Set<String> getUserPermissionCodes(Long userId) {
        logger.debug("查询用户权限编码，用户ID: {}", userId);
        
        List<Permission> permissions = getUserPermissions(userId);
        return permissions.stream()
                .map(Permission::getPermissionCode)
                .collect(Collectors.toSet());
    }

    @Override
    public List<ResourceDto> getUserMenus(Long userId) {
        logger.debug("查询用户菜单，用户ID: {}", userId);
        
        try {
            List<Resource> menuResources = resourceMapper.selectMenusByUserId(userId);
            return buildResourceTree(menuResources, 0L);
        } catch (Exception e) {
            logger.error("查询用户菜单失败，用户ID: {}, 异常: {}", userId, e.getMessage(), e);
            throw new RuntimeException("查询用户菜单失败", e);
        }
    }

    @Override
    public UserPermissionDto getUserPermissionInfo(Long userId) {
        logger.debug("查询用户完整权限信息，用户ID: {}", userId);
        
        try {
            UserPermissionDto userPermissionDto = new UserPermissionDto();
            
            // 1. 查询用户角色
            List<Role> roles = getUserRoles(userId);
            List<RoleDto> roleDtos = roles.stream().map(this::convertToRoleDto).collect(Collectors.toList());
            userPermissionDto.setRoles(roleDtos);
            
            // 2. 查询用户权限
            List<Permission> permissions = getUserPermissions(userId);
            List<PermissionDto> permissionDtos = permissions.stream().map(this::convertToPermissionDto).collect(Collectors.toList());
            userPermissionDto.setPermissions(permissionDtos);
            
            // 3. 设置权限编码集合
            Set<String> permissionCodes = permissions.stream()
                    .map(Permission::getPermissionCode)
                    .collect(Collectors.toSet());
            userPermissionDto.setPermissionCodes(permissionCodes);
            
            // 4. 查询用户菜单
            List<ResourceDto> menus = getUserMenus(userId);
            userPermissionDto.setMenus(menus);
            
            // 5. 设置主要角色（兼容性）
            if (!roles.isEmpty()) {
                userPermissionDto.setRole(roles.get(0).getRoleCode());
            }
            
            logger.debug("用户权限信息查询成功，用户ID: {}, 角色数量: {}, 权限数量: {}", userId, roles.size(), permissions.size());
            return userPermissionDto;
        } catch (Exception e) {
            logger.error("查询用户权限信息失败，用户ID: {}, 异常: {}", userId, e.getMessage(), e);
            throw new RuntimeException("查询用户权限信息失败", e);
        }
    }

    @Override
    public boolean hasPermission(Long userId, String permissionCode) {
        logger.debug("检查用户权限，用户ID: {}, 权限编码: {}", userId, permissionCode);
        
        Set<String> userPermissions = getUserPermissionCodes(userId);
        boolean hasPermission = userPermissions.contains(permissionCode);
        
        logger.debug("用户权限检查结果，用户ID: {}, 权限编码: {}, 拥有权限: {}", userId, permissionCode, hasPermission);
        return hasPermission;
    }

    @Override
    public boolean hasRole(Long userId, String roleCode) {
        logger.debug("检查用户角色，用户ID: {}, 角色编码: {}", userId, roleCode);
        
        List<Role> userRoles = getUserRoles(userId);
        boolean hasRole = userRoles.stream()
                .anyMatch(role -> roleCode.equals(role.getRoleCode()));
        
        logger.debug("用户角色检查结果，用户ID: {}, 角色编码: {}, 拥有角色: {}", userId, roleCode, hasRole);
        return hasRole;
    }

    // ============== 私有辅助方法 ==============

    /**
     * 构建资源树
     */
    private List<ResourceDto> buildResourceTree(List<Resource> resources, Long parentId) {
        List<ResourceDto> tree = new ArrayList<>();
        
        for (Resource resource : resources) {
            if (Objects.equals(resource.getParentId(), parentId)) {
                ResourceDto dto = convertToResourceDto(resource);
                dto.setChildren(buildResourceTree(resources, resource.getId()));
                tree.add(dto);
            }
        }
        
        return tree.stream()
                .sorted(Comparator.comparing(ResourceDto::getSortOrder, Comparator.nullsLast(Comparator.naturalOrder())))
                .collect(Collectors.toList());
    }

    /**
     * 转换为角色DTO
     */
    private RoleDto convertToRoleDto(Role role) {
        RoleDto dto = new RoleDto();
        dto.setId(role.getId());
        dto.setRoleCode(role.getRoleCode());
        dto.setRoleName(role.getRoleName());
        dto.setDescription(role.getDescription());
        dto.setStatus(role.getStatus());
        dto.setSortOrder(role.getSortOrder());
        dto.setRemark(role.getRemark());
        return dto;
    }

    /**
     * 转换为权限DTO
     */
    private PermissionDto convertToPermissionDto(Permission permission) {
        PermissionDto dto = new PermissionDto();
        dto.setId(permission.getId());
        dto.setPermissionCode(permission.getPermissionCode());
        dto.setPermissionName(permission.getPermissionName());
        dto.setResourceId(permission.getResourceId());
        dto.setDescription(permission.getDescription());
        dto.setStatus(permission.getStatus());
        return dto;
    }

    /**
     * 转换为资源DTO
     */
    private ResourceDto convertToResourceDto(Resource resource) {
        ResourceDto dto = new ResourceDto();
        dto.setId(resource.getId());
        dto.setParentId(resource.getParentId());
        dto.setResourceCode(resource.getResourceCode());
        dto.setResourceName(resource.getResourceName());
        dto.setResourceType(resource.getResourceType());
        dto.setResourceUrl(resource.getResourceUrl());
        dto.setMethod(resource.getMethod());
        dto.setIcon(resource.getIcon());
        dto.setComponent(resource.getComponent());
        dto.setRedirect(resource.getRedirect());
        dto.setHidden(resource.getHidden());
        dto.setCache(resource.getCache());
        dto.setAffix(resource.getAffix());
        dto.setSortOrder(resource.getSortOrder());
        dto.setStatus(resource.getStatus());
        dto.setRemark(resource.getRemark());
        return dto;
    }
}